﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Web;
using Com.Toook.AutoDownloadHtml.Util;

namespace Com.Toook.AutoDownloadHtml.DownloadHtml.ParseObj
{
    public class ParseXmlToStep
    {
        private string path = null; //HttpContext.Current.Request.PhysicalApplicationPath + "\\App_Data\\NewsParseRule_Sohu.xml";
        //private string kindId = null;

        private string kindSourceUrl = null;
        /// <summary>
        /// 分类原始页面URL
        /// </summary>
        public string KindSourceUrl
        {
            get
            {
                return kindSourceUrl;
            }            
        }
        private Step initStep = null;
        /// <summary>
        /// 分类页面根元素解析步骤
        /// </summary>
        public Step InitStep
        {
            get
            {
                return initStep;
            }            
        }
        private int linkTextLength = 0;
        /// <summary>
        /// 详细页面超链接标题的最小长度，小于此长度的链接丢弃。为0 不限制长度
        /// </summary>
        public int MinLinkTextLength
        {
            get
            {
                return linkTextLength;
            }
            set
            {
                linkTextLength = value;
            }
        }
        private PageRule pageRule;
        /// <summary>
        /// 分类有多个分页时的分页规则
        /// </summary>
        public PageRule PageRule
        {
            get
            {
                return pageRule;
            }            
        }
        /// <summary>
        /// 根据一个网站的配置文件，解析出全部分类的Step对象 List&lt;List&lt;Rule&gt;&gt;
        /// </summary>
        /// <param name="xmlPath">网站的配置文件路径</param>
        public ParseXmlToStep(string xmlPath)
        {
            this.path = xmlPath;
        }
        
        /// <summary>
        /// 获取一个分类对应的规则列表List&lt;Rule&gt;
        /// </summary>
        /// <param name="kindId">分类kind节点的id名称</param>       
        /// <returns></returns>
        public List<Rule> GetRuleListByKindId(string kindId)
        {          
            XmlNode kindNode = GetKindNodeFromXml(kindId);
            //获取分类页面原始url
            kindSourceUrl = kindNode.Attributes["url"].Value;
            this.linkTextLength = int.Parse(kindNode.Attributes["minTitleLen"].Value);
            //获取分页规则
            XmlNode pageNode = kindNode.SelectSingleNode("pageRule");
            if (pageNode != null)
            {
                this.pageRule = InitPageRule(pageNode);
            }

            XmlNode initNode = kindNode.SelectSingleNode("initElements");
            initStep = ParseStep(initNode);//获取分类根元素解析步骤

            XmlNodeList ruleList = kindNode.SelectNodes("rule");
            List<Rule> ruleListSteps = ParseRuleList(ruleList);

            return ruleListSteps;
        }
        /// <summary>
        /// 如果分类有多个分页，解析出分页规则(如电影分类)
        /// </summary>
        /// <param name="pageNode"></param>
        private PageRule InitPageRule(XmlNode pageNode)
        {
            PageRule pageRule = new PageRule();
            XmlNodeList specialPage = pageNode.SelectNodes("specialPage");
            if (specialPage != null)
            {
                pageRule.SpecialUrl = new List<string>(specialPage.Count);
                foreach (XmlNode n in specialPage)
                {
                    pageRule.SpecialUrl.Add(n.InnerText);
                }
            }
            else
            {
                pageRule.SpecialUrl = new List<string>();//没有特殊页的只初始化，不赋值
            }

            try
            {
                pageRule.StartNum = int.Parse(pageNode.SelectSingleNode("startNum").InnerText);
                pageRule.MaxNum = int.Parse(pageNode.SelectSingleNode("maxNum").InnerText);
                pageRule.StartStr = pageNode.SelectSingleNode("startStr").InnerText;
                pageRule.EndStr = pageNode.SelectSingleNode("endStr").InnerText;
                pageRule.BaseUrl = pageNode.SelectSingleNode("baseUrl").InnerText;
                pageRule.PageType = (PageType)Enum.Parse(typeof(PageType), pageNode.SelectSingleNode("rule").InnerText, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("InitPageRule()错误。", ex);
            }
            return pageRule;
        }        
       
        /// <summary>
        /// 获取配置文件中指定分类的XmlNode节点
        /// </summary>
        /// <returns></returns>
        private XmlNode GetKindNodeFromXml(string kindId)
        {
            XmlDocument docXml = new XmlDocument();
            docXml.Load(path);
            XmlElement root = docXml.DocumentElement;

            XmlNodeList kinds = root.SelectNodes("kind");
            foreach (XmlNode kind in kinds)
            {
                if (kindId == kind.Attributes["id"].Value)
                {
                    return kind;
                }
            }

            LogHelper.Log.Error("指定的kindId=" + kindId + "不存在。" + path);
            throw new Exception("指定的kindId=" + kindId + "不存在。" + path);
        }
       
        /// <summary>
        /// 将一个网站所有分类kind 解析为对应的 kindList
        /// </summary>
        /// <param name="kinds">一个网站配置文件中的所有kind节点</param>
        /// <returns></returns>
        private List<List<Rule>> ParseKinkList(XmlNodeList kinds)
        {
            //根据网站分类数初始化kindList
            List<List<Rule>> kindList = new List<List<Rule>>(kinds.Count);

            //获取各个分类
            foreach (XmlNode kind in kinds)
            {
                //一个分类可能有多个规则rule
                XmlNodeList rules = kind.SelectNodes("rule");
                List<Rule> ruleList = ParseRuleList(rules);
                kindList.Add(ruleList);
            }
            return kindList;
        }

        /// <summary>
        /// 将分类中的每个规则rule解析为对应的 ruleList
        /// </summary>
        /// <param name="rules">一个分类kind下的多个rule节点</param>
        /// <returns></returns>
        private List<Rule> ParseRuleList(XmlNodeList rules)
        {
            List<Rule> ruleList = new List<Rule>(rules.Count);//一个分类可能有多个解析规则

            foreach (XmlNode rule in rules)
            {
                XmlNodeList steps = rule.ChildNodes; //获取step和leaf 节点
                Rule stepList = ParseRule(steps);
                ruleList.Add(stepList);
            }

            return ruleList;
        }
        /// <summary>
        /// 解析出每个Step和Leaf,添加到Rule
        /// </summary>
        /// <param name="steps"></param>
        /// <returns></returns>
        private Rule ParseRule(XmlNodeList steps)
        {
            Rule rule = new Rule();//一个规则rule对应一个StepList        
            foreach (XmlNode stepNode in steps)
            {
                
                if (stepNode.Name == "step")
                {
                    Step step = ParseStep(stepNode);//将xml中的每个step节点解析为Step对象
                    rule.AddStep(step);
                }
                else if (stepNode.Name == "leaf")
                {
                    Step step = ParseStep(stepNode);//将xml中的每个step节点解析为Step对象
                    rule.AddLeaf(step);
                }
                else if (stepNode.Name == "multiLeaf") 
                {
                    ParseMultiLeaf(rule, stepNode);
                }
                else
                {
                    LogHelper.Log.Error("ParseRule() stepNode.Name 不是step、leaf和multiLeaf，不合法。文件：" + this.path);
                }
            }

            return rule;
        }
        /// <summary>
        /// 将链接、图片等多个叶节点元素解析、添加到Rule.MultiLeaf中
        /// </summary>
        /// <param name="rule"></param>
        /// <param name="multiNode"></param>
        private void ParseMultiLeaf(Rule rule, XmlNode multiNode) 
        {
            rule.MultiLeaf = new Leaf();
            string[] nodeNames = { "linkUrl", "linkText", "imgUrl", "imgText", "description", "actor", "director", "year", "area" };
            foreach (string nodeName in nodeNames)
            {
                XmlNode node = multiNode.SelectSingleNode(nodeName);               
                if (node != null)
                {
                    XmlNodeList steps = node.SelectNodes("stepLeaf");
                    //将linkUrl等节点的step解析添加到MultiLeaf对应的列表中
                    foreach (XmlNode s in steps)
                    {
                        Step step = ParseStep(s);
                        switch (nodeName)
                        {
                            case "linkUrl":
                                rule.MultiLeaf.AddLinkUrlStep(step);
                                break;
                            case "linkText":
                                rule.MultiLeaf.AddLinkTextStep(step);
                                break;
                            case "imgUrl":
                                rule.MultiLeaf.AddImgUrlStep(step);
                                break;
                            case "imgText":
                                rule.MultiLeaf.AddImgTextStep(step);
                                break;
                            case "description":
                                rule.MultiLeaf.AddDescriptionStep(step);
                                break;
                            case "actor":
                                rule.MultiLeaf.AddActorStep(step);
                                break;
                            case "director":
                                rule.MultiLeaf.AddDirectorStep(step);
                                break;
                            case "year":
                                rule.MultiLeaf.AddYearStep(step);
                                break;
                            case "area":
                                rule.MultiLeaf.AddAreaStep(step);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }
        
        /// <summary>
        /// 将xml中的每个step节点解析为Step对象
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private Step ParseStep(XmlNode node)
        {
            Step step = new Step();
            step.AttrName = node.Attributes["name"].Value;
            step.AttrValue = node.Attributes["value"] == null ? "" : node.Attributes["value"].Value;
            string getBy = node.Attributes["getBy"].Value;
            try
            {
                step.GetBy = (ByType)Enum.Parse(typeof(ByType), getBy, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("ParseStep() getBy=" + getBy + "不合法, 文件：" + path, ex);
            }           
        
            return step;
        }
/////////////////////////////////////////////////////////////////////////////////////
        //private Step ParseStep(XmlNode node)
        //{
        //    Step step = new Step();
        //    step.AttrName = node.Attributes["name"].Value;
        //    step.AttrValue = node.Attributes["value"] == null ? "" : node.Attributes["value"].Value;
        //    string getBy = node.Attributes["getBy"].Value;
        //    switch (getBy)
        //    {
        //        case "Id":
        //            step.GetBy = ByType.Id;
        //            break;
        //        case "Class":
        //            step.GetBy = ByType.Class;
        //            break;
        //        case "Tag":
        //            step.GetBy = ByType.Tag;
        //            break;
        //        case "Attr":
        //            step.GetBy = ByType.Attr;
        //            break;
        //        case "AttrStart":
        //            step.GetBy = ByType.AttrStart;
        //            break;
        //        case "ContainText":
        //            step.GetBy = ByType.ContainText;
        //            break;
        //        case "ContainOwnText":
        //            step.GetBy = ByType.ContainOwnText;
        //            break;
        //        case "MatchText":
        //            step.GetBy = ByType.MatchText;
        //            break;
        //        case "MatchOwnText":
        //            step.GetBy = ByType.MatchOwnText;
        //            break;
        //        case "IndexEquals":
        //            step.GetBy = ByType.IndexEquals;
        //            break;
        //        case "IndexLessThan":
        //            step.GetBy = ByType.IndexLessThan;
        //            break;
        //        case "IndexGreaterThan":
        //            step.GetBy = ByType.IndexGreaterThan;
        //            break;
        //        //属性名，属性值
        //        case "AttrValue":
        //            step.GetBy = ByType.AttrValue;
        //            break;
        //        case "AttrValueStart":
        //            step.GetBy = ByType.AttrValueStart;
        //            break;
        //        case "AttrValueEnd":
        //            step.GetBy = ByType.AttrValueEnd;
        //            break;
        //        case "AttrValueContain":
        //            step.GetBy = ByType.AttrValueContain;
        //            break;
        //        case "AttrValueMatch":
        //            step.GetBy = ByType.AttrValueMatch;
        //            break;
        //        case "AttrValueContainDateNow":
        //            step.GetBy = ByType.AttrValueContainDateNow;
        //            break;
        //        default:
        //            LogHelper.Log.Error("ParseStep() getBy=" + getBy + "不合法, 文件：" + path);
        //            break;
        //    }
        //    return step;
        //}

        /*
       private void GetStepListFromXml()
       {
           XmlDocument docXml = new XmlDocument();
           docXml.Load(path);
           XmlElement root = docXml.DocumentElement;

           XmlNodeList kinds = root.SelectNodes("kind");
           //根据网站分类数初始化kindList
           List<List<Rule>> kindList = new List<List<Rule>>(kinds.Count);

           //获取各个分类
           foreach (XmlNode kind in kinds)
           {
               //一个分类可能有多个规则rule
               XmlNodeList rules = kind.SelectNodes("rule");
               List<Rule> ruleList = ParseRuleList(rules);
               kindList.Add(ruleList);
           }           
       }
       */
        /// <summary>
        /// 根据网站指定分类的配置文件，解析出此分类的Step对象
        /// </summary>
        /// <param name="xmlPath">网站的配置文件路径</param>
        /// <param name="kindId">分类kindId</param>
        //public ParseXmlToStep(string xmlPath, string kindId)
        //{
        //    this.path = xmlPath;
        //    this.kindId = kindId;
        //}
        /// <summary>
        /// 获取网站所有分类对应的Step对象列表
        /// </summary>
        /// <returns></returns>
        /*
        public List<List<Rule>> GetAllKindStepList()
        {
            XmlNodeList kindNodeList = GetKindNodeListFromXml();
            List<List<Rule>> kindListSteps = ParseKinkList(kindNodeList);
            return kindListSteps;
        }
        /// <summary>
        /// 获取配置文件中所有分类的XmlNodeList
        /// </summary>
        /// <returns></returns>
        private XmlNodeList GetKindNodeListFromXml()
        {
            XmlDocument docXml = new XmlDocument();
            docXml.Load(path);
            XmlElement root = docXml.DocumentElement;

            XmlNodeList kinds = root.SelectNodes("kind");
            return kinds;
        }
         */
    }
}
